Du må være registrert og logget inn for å kunne legge ut innlegg på freak.no
X
LOGG INN
... eller du kan registrere deg nå
Dette nettstedet er avhengig av annonseinntekter for å holde driften og videre utvikling igang. Vi liker ikke reklame heller, men alternativene er ikke mange. Vær snill å vurder å slå av annonseblokkering, eller å abonnere på en reklamefri utgave av nettstedet.
  9 1842
Hei, alle sammen.

Jeg har to spørsmål. Det første er at jeg prøver å lage et enkelt rundebasert spill, og jeg prøver å få til at det skal være X antall runders delay fra spilleren gjør en handling til den trer i kraft. Jeg tenker at det må være en funksjon som tar antall runders delay som argument, men da blir problemet at man ikke kommer ut av funksjonen før handlingen er utført.
Videre tenkte jeg at jeg måtte lage en if-else som sjekket den globale variabelen nRounds, men da blir problemet at hvis jeg lager en funksjon á lá dette:

Kode

int delay(const int* nRounds, int nDelay) {
nTarget = (nRounds + nDelay)
(...)
}
Hver gang programmet kommer til delay() blir det opprettet en ny nTarget, også blir delayen konstant dyttet fremover og aldri utført. Jeg vedder på at det dreier seg om dynamisk minne eller static. Jeg kan lite om det. Håper noen skjønner hva jeg spør om, og kan hjelpe.
Forresten, så må selvsagt funksjonen kunne brukes mange ganger, og av flere brukere samtidig. Altså hvis en oppgave ikke er ferdig utført, må man fortsatt kunne sette i gang en ny prosess. Rotete forklart, men jeg håper dere skjønner.


Spørsmål nummer to er at jeg vil at det i nevnte spill skal være mulig å skrive inn hvor mange spillere det skal være med, og så skal programmet opprette X antall kopier av klassen Person. Jeg har laget et tullete eksempel som kanskje hjelper til med å forklare hva jeg mener:

Kode

// Person.cpp : main project file.

#include "stdafx.h"
#include <iostream>
#include "CPerson.h" // Definerer class Person.
using namespace std;

int main()
{
	cout << "How many players? ";
	int nPersons;
	cin >> nPersons;

	for(int i=1; i <= nPersons; i++) {
		Person Person_i;
		}

	system("pause");

    return 0;
}
Linjen Person Person_i; er nøkkelen. Den skal liksom i tur og orden opprette det antallet objekter av klassen Person som brukeren skrev inn.
Lar dette seg gjøre?
På forhånd takk for all hjelp.
Sist endret av Bolletott; 16. juni 2012 kl. 16:37.
Spørsmål 1: Problemet er at alt som deklareres i en funksjon vil slutte å eksistere i det du forlater funksjonen, og minnet det opptok frigjøres (med unntak av ting som deklareres dynamisk med new). Det samme gjelder for øvrig ting som deklareres i if-blokker, for-løkker også videre – les om scope for å lære mer om dette, for eksempel her. Du må derfor ha den deklarert et annet sted for å ikke ende i en knipe. Nå vet ikke jeg hvordan du har strukturert resten av programmet og hvordan spillet er ment å fungere, men det kan kanskje være naturlig å deklarere delay-variabelen i spillerklassen? Eller i funksjonen som styrer spillets gang, som for eksempel main? Eventuelt kan du lage de globale, selv om det som regel gir en ryddigere struktur å unngå de. Det er i det hele tatt vanskelig å gi et konkret svar på hvordan du best løser dette når man vet så lite om programmet ellers.

Spørsmål 2: Du kan for eksempel lage en array med Person-pekere av en bestemt lengde, også bruke new for å deklarere de du trenger. Men da bør du også huske på såkalt garbage collection og slette de med delete-operatoren når de ikke lenger skal eksistere. Deklareringen kan se slik ut:

Kode

int main()
{
  cout << "How many players? ";
  int nPersons;
  Person persons [50];  // max 50 spillere (49 pga 1-indeksering), bør kontrollere at nPersons < 50
  cin >> nPersons;

  for(int i=1; i <= nPersons; i++) {
    person[i] = new Person;  // disse bør alle slettes med 'delete' senere
  }
  return 0;
}
Men, selv om du bør forstå hvordan og hvorfor dette fungerer, så vil det i praksis være lettere å bruke en vector. Det er en datatype som fungerer som en dynamisk array hvor du kan legge til og slette elementer uten å sette noen initiell grense, og uten særlig med mikkmakk. Koden kan da se omtrent slik ut:

Kode

#include <vector.h>
int main()
{
  cout << "How many players? ";
  int nPersons;
  vector<Person> persons;
  cin >> nPersons;

  for(int i=1; i <= nPersons; i++) {
    Person a_person;
    persons.push_back(a_person);
  }
  return 0;
}
Til slutt vil jeg anbefale at du venner deg til null-indeksering. Det er slik alle arrays fungerer, og det er generelt vanlig å begynne å telle fra og med null i programmeringsverdenen. Noe annet vil bare bli knotete senere, du kaster bort en minneplassering hver gang du bruker en sekvens med elementer i et array, og standard datatyper som vector, deque og list begynner alltid fra plassering 0 uansett.
Sitat av Provo Vis innlegg
Spørsmål 2: Du kan for eksempel lage en array med Person-pekere av en bestemt lengde, også bruke new for å deklarere de du trenger. Men da bør du også huske på såkalt garbage collection og slette de med delete-operatoren når de ikke lenger skal eksistere. Deklareringen kan se slik ut:

Kode

int main()
{
  cout << "How many players? ";
  int nPersons;
  Person persons [50];  // max 50 spillere (49 pga 1-indeksering), bør kontrollere at nPersons < 50
  cin >> nPersons;

  for(int i=1; i <= nPersons; i++) {
    person[i] = new Person;  // disse bør alle slettes med 'delete' senere
  }
  return 0;
}
Vis hele sitatet...
Det skal være Person* persons[50].
Også hopper du fortsatt over array index 0 som OP gjør, det burde heller vært slik:

Kode

for (int i = 0; i < nPersons; ++i) {
 ...
}
Men som Provo sa så er vector å foretrekke. Alltid bruk det STL har å tilby.
Sist endret av TanteSpiker; 16. juni 2012 kl. 18:32.
Sitat av boblehest Vis innlegg
Det skal være Person* persons[50].
Vis hele sitatet...
Slurv fra min side. Takk for rettelsen.

Sitat av boblehest Vis innlegg
Også hopper du fortsatt over array index 0 som OP gjør
Vis hele sitatet...
Det var med hensikt, for å beholde strukturen til Bolletott slik at fokuset var på det som skulle forklares. Som jeg skrev under bør man venne seg til nullindeksering først som sist.
Sist endret av Provo; 16. juni 2012 kl. 18:42.
Provo:
Ja, jeg reagerte bare på det siden du faktisk sløser minne ved å ikke bruke det. Tenkte at du burde rette på det, ved å f.eks. bruke person[i-1] i loopen.

Bolletott:
Angående spørsmål 1 så kan du lage en klasse som representerer en handling, som du legger til en liste med handlinger på vent. Nå vet jeg ikke helt hva slags handlinger det er, men de burde gå ann å representere på et vis.

Kode

class Action {
 private:
  int type; //Type handling, men som sagt har jeg ikke peiling på hva slags handlinger det er snakk om, så du må nok ha noe litt mer avansert vil jeg anta.
  unsigned int remaningDelay;

 public:
  Action(int delay) : remainingDelay(delay) {}
  void Update() { if (--remainingDelay == 0) [...] }
  [...]
};
Så kan du oppdatere alle handlingene hver runde.
Sist endret av TanteSpiker; 16. juni 2012 kl. 18:51.
Vil bare berke at type i så fall burde være en "enum"; og det at du har valgt å kommentere hva type er noe noe ikke er bra - et tydelig tegn på at variabelnavnet ikke er bra nok og må byttes.
Det boblehest har foreslått er en tilnærming til Command-patternet Der lager man altså en klasse per handling. Du kan bruke en variant av dette ved å ha en delaycommand som inneholder en annen kommando den kan delaye. Altså når du oppretter en delay command sender du inn commando som skal delayes og et antall runder den skal delayes. Du kan telle ned antall runder hver gang du kaller execute på delaykommandoen, og når det er 0 runder igjen kjører du den egentlige kommandoen.
Sitat av etse Vis innlegg
Vil bare berke at type i så fall burde være en "enum"; og det at du har valgt å kommentere hva type er noe noe ikke er bra - et tydelig tegn på at variabelnavnet ikke er bra nok og må byttes.
Vis hele sitatet...
Enig i at det burde vært enum, men nå ville jeg holde eksempelet kort og gadd ikke lage en ekstra enum klasse.

Det andre poenget ditt er jeg helt uenig i though, jeg prøver å forklare klassen for OP, hadde ikke kommentert den ellers.
Trådstarter
8 0
Takk alle sammen for gode svar. Jeg skjønner ikke at jeg ikke tenkte på scope, men selvfølgelig er det problemet. Jeg tror jeg har fått svar på spørsmål to, men det er litt usikkerhet rundt hva jeg mener på spørsmål 1, så her kommer litt tilleggsopplysninger:

Spillet er veldig på tankeplanet enda, men se for dere noe som dette: Jeg har 50 000 dollar. Jeg vil kjøpe en hund. Den koster $1000. Det tar tre runder fra jeg avslutter runden jeg "bestilte" hunden i, til jeg får den. Når jeg trykker på knappen "Kjøp", skal det trekkes $1000 fra kontoen, og så skal programmet legge inn delayen, og etter tre runder får jeg hunden. Men her kommer det kritiske: Spiller B skal samme runde (en runde er over når alle spillerne har gjort sine handler) kjøpe en moped. Det koster $10 000, og det tar seks runder før han får den.
Derfor tenker jeg noe sånt som en klasse som kan behandle flere oppgaver parallelt, og med forskjellig delay. Derfor funker verken en "handlingskø" eller en global delay, for man kan fort trenge mange delays samtidig.
Jeg veit jeg er litt ambisiøs i forhold til mitt nivå, men allikevel. Takk for hjelpen så langt og videre.

(Forresten, i mitt forsvar: Jeg veit at man starter å telle fra 0 i programmering, men siden dette er objekter som representerer spillere, valgte jeg å begynne på 1 allikevel for Spiller nummer 0 gir ingen mening.)
Sitat av Bolletott Vis innlegg
Derfor tenker jeg noe sånt som en klasse som kan behandle flere oppgaver parallelt, og med forskjellig delay. Derfor funker verken en "handlingskø" eller en global delay, for man kan fort trenge mange delays samtidig.
Vis hele sitatet...
Det var det som var meningen med eksempelet jeg postet over, du bruker klassen til å representere en enkelt ordre, så har du en annen som tar seg av listen over alle.

For å utvide eksempelet litt:

Kode

enum class ItemType { SHOVEL, BUCKET };

class Action {
 private:
  ItemType type;
  const Player& recipient;
  unsigned int remaningDelay;

 public:
  Action(unsigned int delay, ItemType type, const Player& player) : remainingDelay(delay), type(type), recipient(player) {}
  bool Update();
};

bool Action::Update() {
  if (remaingDelay == 0) {
    return true;
  }

  if (--remainingDelay == 0) {
    recipient.GiveItem(item);
    return true;
  }

  return false;
}

class PendingActions {
 public:
  void AddAction(const Action*);
  void Update();

 private:
  std::list<Action*> actions;
};

void PendingActions::AddAction(const Action* action) {
  actions.push_back(action);
}

void PendingActions::Update() {
  for (auto action = actions.begin(); action != list.end();) {
    if (Action.Update()) {
      delete *action;
      action = actions.erase(action);
    } else {
      ++action;
    }
  }
}
Så kunne du brukt pendingActions.AddAction(new Action(3, ItemType::SHOVEL, player)), som da etter 3 updates hadde gitt en 'shovel' til 'player', for så å slette den fra listen.

Koden over kompilerer ganske sikkert ikke; jeg har ikke testet den, og jeg programmerer lite for tiden.

Sitat av Bolletott Vis innlegg
(Forresten, i mitt forsvar: Jeg veit at man starter å telle fra 0 i programmering, men siden dette er objekter som representerer spillere, valgte jeg å begynne på 1 allikevel for Spiller nummer 0 gir ingen mening.)
Vis hele sitatet...
Du kan begynne å telle fra 0 internt, men du trenger ikke vise det til spillerene. Spiller i kaller du bare for i+1 når du printer det.
Sist endret av TanteSpiker; 18. juni 2012 kl. 16:45.