Instance exists – problem z ujemnymi wartościami

Dodany: 28 stycznia, 2011 | Kategoria: Game Maker

W GM jest dość ciekawy byk. Stworzyłem tablicę w której zapisuję id obiektów i założyłem, że brak obiektu oznaczę poprzez cyfrę -1. Niestety coś nie chciało działać jak powinno i skrypt który miał owe obiekty z listy niszczyć tylko gdy istnieją, usuwał totalnie inny obiekt niż powinien. Szukałem zatem kilkadziesiąt minut i… okazało się, że oba zapisy są równoważne:

1
instance_exists(-1) == instance_exists(self)

Poszukałem więc jeszcze trochę, i tym oto sposobem wyszło, ze każda z super zmiennych ma przypisaną ujemną wartość:

1
2
3
4
5
self == -1;
other == -2;
all == -3;
noone == -4;
global == -5;

Uważajcie więc tworząc gry, żeby się nie nadziać :)

Tagi: , , , , , , , , , , Brak komentarzy »

Metoda siecznych, Metoda Newtona

Dodany: 24 stycznia, 2011 | Kategoria: Inne

Ostatnio w ramach metod obliczeniowych robiłem pewne zadanko, które skojarzyło mi się z artykułem Platyny zamieszczonym na GMCLANie dotyczącym przeszukiwania binarnego i znajdywania pierwiastka danej liczby. W tym przypadku szukamy co prawda zupełnie innych pierwiastków, bo tych z równań, ale też zwiększamy dokładność wraz z każdym przejściem.

Samo zadanie:
Równanie x5 + 6x4 – 20x3 + 2x3 + 7x – 2 = 0 ma dwa pierwiastki bliskie 0.42. Wyznaczyć je Metodą Newtona oraz Metodą Siecznych.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <stdio.h>
#include <math.h>

// funkcja z A2
double f(double x)
{
    return pow(x,5) + 6*pow(x,4)
        - 20*pow(x,3) + 2 * pow(x,2) + 7 * x - 2;
}

// metoda siecznych
double Sieczne(double xn_1, double xn, double e, int m)
{
    int n;
    double d;
    for (n = 1; n <= m; n++)
    {
        d = (xn - xn_1) / (f(xn) - f(xn_1)) * f(xn);
        if (fabs(d) < e)
            return xn;
        xn_1 = xn;
        xn = xn - d;
    }
    return xn;
}

// pochodna
double p(double x)
{
    return 5*pow(x,4)+24*pow(x,3)-60*pow(x,2)+4*x+7;
}

double Newton(double x, double e, double m) {
    double h;
    int n;

    for (n = 1; n<=m; n++)
    {
        h = - (f(x) / p(x));
        if (fabs(h)<5E-11) {
                return x;
        }
        x = x + h;
    }

    return x;
}

int main(void)
{
/* 5E-11 to różnica poniżej której przestajemy szukać,
w przeciwnym wypadku próbujemy max. 100 razy
i ten wynik uznajemy za najdokładniejszy */


printf("%0.15f\n", Sieczne(0.30, 0.42, 5E-11, 100));
printf("%0.15f\n", Sieczne(0.42, 0.50, 5E-11, 100));

printf("%0.15f\n", Newton(0.30,5E-11,100));
printf("%0.15f\n", Newton(0.50,5E-11,100));
return 0;
}
Tagi: , , , , , , , , , , , , Brak komentarzy »

Yii – renderowanie widoków z dowolnego folderu

Dodany: 22 stycznia, 2011 | Kategoria: Yii

Wyświetlanie widoku z innego kontrolera/folderu/ścieżki w tym obecnym.
Sprawiło mi to trochę problemu, a sprawa taka prosta…

$this->render('/index'); – wyrenderuje nazwaKontrolera/index.php
$this->render('//index'); – wyrenderuje views/index.php
$this->render('//folder/plik'); – wyrenderuje views/folder/plik.php

Tagi: , , , , , Brak komentarzy »

Yii – gettery do AR

Dodany: 22 stycznia, 2011 | Kategoria: Yii

Modele korzystające z AR zwracają dane bezpośrednio z bazy, co jednak gdy chcemy np. przerobić datę tam zapisaną z postaci unix na ludzką ??
Teoretycznie najprościej było by po wczytaniu rekordu zaktualizować go (np. $this->time = date('H:i:s', $time) w afterFind()), ale ma to jedną wadę – do formularzy edycyjnych trafi ta zmodyfikowana data, a przecież do bazy trafia ona jako INT, więc się wszystko sypnie.
Odpowiedź prosta – napisać nową metodę gettera w modelu, która zwraca datę, np. getCzytelnaData():

1
2
3
public function getCzytelnaData() {
    return date('H:i:s', $this->data);
}

Potem możemy wypisać taką datę w widoku zamiast $this->data które zwraca np. 1123123123, to $this->czytelnaData (metoda magiczna CActiveRecord::__get), a do widgetów wpisujemy jako pole z modelu 'czytelnaData’ :) Takiego pola nie ma w bazie, ale to nie znaczy, ze nie musi być w modelu – w ten sposób mozna sporo bajerów zrobić ;)

Tagi: , , , Brak komentarzy »

Zmienne lokalne, globalne i tymczasowe – GML

Dodany: 21 stycznia, 2011 | Kategoria: Game Maker

(opublikowano na: http://gmclan.org/index.php?czytajart=73)

Zmienne w GM można podzielić na 3 typy: tymczasowe, lokalne i globalne.

Zmienne globalne:

Zmienna globalna to taka, która dostępna jest dla wszystkich obiektów w jednym jej egzemplarzu. GM posiada kilka wbudowanych zmiennych globalnych, np. fps – liczba klatek na sekundę jest jedna dla całej gry. Nie ma innej liczby klatek dla jednego obiektu, innej dla drugiego – z każdego obiektu uzyskamy tą samą wartość w danej chwili.
Własne zmienne globalne poprzedzamy słowem global oraz kropką, po której następuje nazwa tej zmiennej. Przeczytaj dalszą część wpisu »

Tagi: , , , , , , , , 2 komentarze »

Alarmy w GM – jak działają, jak unikać błędów

Dodany: 19 stycznia, 2011 | Kategoria: Game Maker

Alarm to jeden z ważniejszych eventów (zdarzeń) w GM. Czym są alarmy? To tak naprawdę po prostu zmienne pomocnicze, które oznaczają dla nas upływający czas, dzięki czemu możemy wykonać jakiś kod co pewien przedział czasu.
Przykładowo, wystrzał ze strzelby – naboje nie mogą wyskakiwać bez przerwy, bo przecież chwilę trwa „przeładowanie”. Zatem najlepiej aby wylatywały co np. sekundę, lub półtorej. Właśnie do tego przyda się alarm.

Jak działa alarm?

Alarm jak już wspomniałem to po prostu taka pomocnicza zmienna. Domyślnie, alarmów jest 12 (zmienne alarm[0] – alarm[11]). Wartość ustawiona w alarmie oznacza liczbę kroków (eventów step), za które nastąpi ich wywołanie ( w trakcie jednej sekundy event step jest wykonywany dokładnie tyle razy ile wynosi wartość room_speed danej planszy – domyślnie 30 eventów na sekundę, co równa się też 30 klatkom na sekundę obrazu). Gdy dochodzi do zera, wykonuje się kod eventu alarm, a on sam ustawiany jest na -1. Gdy równa się -1 nie jest już zmniejszany.

alarm[X] > 0 – w każdym kolejnym kroku alarm jest zmniejszany o 1 aż do zera
alarm[X] = 0 – następuje wywołanie zdarzenia / eventu AlarmX, alarm[X] ustawiamy na -1, przestajemy go zmniejszać
alarm[X] = -1 – nie dzieje się nic, alarm jest nieaktywny

Zatem, jeżeli chcemy aby jakieś zdarzenie następowało co sekundę, należy ustawić alarm[0] na room_speed, lub 30 (jeżeli tyle wynosi room_speed danej planszy).

Najczęściej popełniane błędy

Najczęściej popełniany błąd, to wywołanie alarmów w zdarzeniach (eventach) step, lub kolizji.
Przykładowo, jeżeli obj_bohater jest blisko obj_przeciwnik, to przeciwnik ma strzelać.
Pierwszy kod jaki przychodzi do głowy wygląda tak (kod dla obj_przeciwnik, event step – sprawdzany w każdym kroku):

1
2
3
4
if distance_to_object(obj_bohater)<100
{
alarm[0] = 10;
}

Oczywiście kod jest BŁĘDNY! Dlaczego? Zastanówmy się. Jak wcześniej powiedziałem, w każdym stepie alarm zmniejszany jest o 1 aż dojdzie do 0.
Wykonujemy pierwszy krok. Odejmujemy 1 i nasz alarm[0] = 9. Następnie sprawdzany jest kod podany w step. Bohater stoi nadal blisko przeciwnika, zatem warunek jest spełniony i alarm[0] ustawiamy na 10.
W kolejnym kroku alarm znów sam zmniejsza się o 1, ale my znów ustawiamy go na 10. W ten sposób zatrzymaliśmy alarm w miejscu! Zacznie odliczać się dopiero, gdy bohater odsunie się od przeciwnika – i dopiero wtedy przeciwnik zacznie strzelać. Tego przecież nie chcemy.
Jak wspomniałem, alarm jest nieaktywny gdy jest równy -1. Wykorzystajmy ten fakt do poprawienia naszego kodu. Można to zrobić w dowolny sposób, ja podam dwa.

1
2
3
4
if distance_to_object(obj_bohater)<100 and alarm[0] = -1
{
alarm[0] = 10;
}
1
2
3
4
if distance_to_object(obj_bohater)<100
{
if alarm[0] = -1 then alarm[0] = 10;
}

Oczywiście zakładam, że w zdarzeniu Alarm0 mamy kod tworzenia pocisku.

Mam nadzieję, że wyjaśniłem wystarczająco działanie alarmów.

Własny alarm

Na podstawie wiedzy którą masz, powinieneś być w stanie stworzyć nieskończenie wiele alarmów na własne potrzeby. Przykładowy kod własnego alarmu (w Create obiektu definiujemy zmienną moj_alarm = -1;), umieszczony w zdarzeniu Step.

1
2
3
4
5
6
7
8
9
if moj_alarm>0
{
moj_alarm -= 1;
}
else if moj_alarm = 0
{
moj_alarm = -1;
// kod do wykonania naszego alarmu, np. instance_create(x,y,obj_bullet);
}

Ustawienie zmiennej moj_alarm na większą od zera spowoduje wykonanie się kodu za podaną ilość kroków.

Tak właśnie działają alarmy – ale w przypadku wbudowanych zmiennych alarm[0] – alarm[11] powyższy kod Game Maker wykonuje za nas.

Tagi: , , , , , , , Brak komentarzy »

GM – Operacje na zmiennych

Dodany: 18 stycznia, 2011 | Kategoria: Game Maker

W Game Makerze wyróżniamy dwa typy zmiennych:

1) Zmienne liczbowe (real) – są to po prostu liczby rzeczywiste, np. a = 5, a=17.32, a = $A1 (szesnastkowo 161);

2) Łańcuchy tekstowe (string) – są to zmienne zawierające tekst, np. a = 'tekst’, lub a = „tekst”;

Należy jednak zauważyć, że a=5 to nie to samo co a=’5′, gdyż tekst nie jest liczbą i na odwrót i tych dwóch typów nie wolno bezpośrednio ze sobą porównywać.

Do zamiany liczby w tekst służy funkcja string(), do zamiany tekstu w liczbę służy funkcja real(), jednak tekst taki może zawierać tylko cyfry, znak minus, kropkę oddzielającą część dziesiętną oraz znak wykładniczy E (np. 1.E+1), bez liter i innych znaków.

Istnieje również wiele funkcji pozwalających na bardziej zaawansowane działania na zmiennych, skupię się jednak tylko na operatorach.

Operacje na łańcuchach tekstu:

Na tekście możemy dokonać dwóch operacji:

1) Konkatenacja, czyli łączenie tekstów: np. a = 'xxx’ + 'yyy’, a+=’xxx’;

2) Konkatenacja tekstu z samym sobą określoną ilość razy, np. a = 5 * 'x’ zwraca 'xxxxx’;

Operacje na liczbach:

Na liczbach można wykonać następne operacje:

Dodawanie: a=5+7; a=a+5, a+=5;

Odejmowanie: a=5-7; a=a-5; a-=5;

Zmiana znaku na przeciwny: a = -a;

Mnożenie: a=5*7; a=a*7; a*=7;

Dzielenie: a=5/7; a=a/7; a/=7; (nie można dzielić przez 0!)

Dzielenie całkowite div (dzielenie bez reszty / z zaokrągleniem w dół): a = 7 div 3 (7 div 3 = 2, bo 7/3 = 2, reszty 1);
Wynikiem dzielenia całkowitego jest zawsze liczba całkowita.

Reszta z dzielenia modulo : a = 7 mod 3 (7 mod 3 = 1, bo 7/3 = 2 reszty 1);
Reszta z dzielenia x mod y jest zawsze liczbą z zakresu od 0 do y-1.

Porównania:
Do porównań funkcji służą następujące operatory:
>, >=, ==, !=, <> , <, <= : większe, większe równe, równe, nierówne, różne, mniejsze, mniejsze równe

W Game Makerze nie ma funkcji post/pre-inkrementacji oraz post/pre-dekrementacji, które występują w innych językach.

Operacje logiczne:

W operacjach logicznych rozróżniamy dwie wartości: true, false. Wartość true (prawdę) oznaczają wszystkie liczby > 0, oraz stała true, wartość false (fałsz) oznaczają wszystkie zmienne <= 0 oraz stała false. Wykorzystywane są głównie do operacji warunkowych (if, while, etc.)

Rozróżniamy następujące operacje logiczne:

&&, AND: prawdziwe, gdy wszystkie wartości wyrażenia mają wartość true, fałszywa w pozostałych przypadkach, np. 7 and 14 to prawda, 7 and -1 to fałsz.

||, OR: prawdziwe, gdy co najmniej jedno wyrażenie jest prawdziwe, fałszywe tylko gdy wszystkie są fałszywe, np. 7 or -1 to prawda, 0 or -1 to fałsz.

^^, XOR: prawdziwe, gdy oba argumenty są sobie przeciwne, fałszywa, gdy są takie same, np. 7 xor -1 to prawda, 7 xor 14 to fałsz

!: negacja, zamienia prawdę w fałsz i na odwrót, np. x = !7 to fałsz, x = !0 to prawda, x = !x zamienia prawdę w fałsz i na odwrót

Operacje bitowe:

Operacje bitowe to operacje, które zachodzą bezpośrednio na bitach liczby w systemie dwójkowym, np. liczba 12 to binarnie 1100.

>> : przesunięcie podanej ilości bitów w liczbie w prawo, poprzez usunięcie bitów na najmłodszej pozycji i dopisanie zer na najstarszej
np. 12 >> 1 to 6, 12 >> 2 to 3 (bo 1100 >> 1 = 0110 czyli 6, 1100 >> 2 = 0011, czyli 3)
Przesunięcie bitów w prawo o 1 jest równoznaczne z operacją dzielenia przez 2.

<< : przesunięcie podanej ilości bitów w liczbie w lewo, poprzez usunięcie bitów na najstarszej pozycji i dopisanie zer na najmłodszej
np. 12 << 1 to 24, 12 << 2 to 48 (bo 1100 << 1 = 1 1000 czyli 24, 1100 << 2 = 11 0000, czyli 48)
Przesunięcie bitów w lewo o 1 jest równoznaczne z operacją mnożenia przez 2.

|, &, ^ : operacje OR, AND, XOR na bitach liczby (działanie wszystkich trzech znajdziesz punkt wyżej)

Przykłady:
12 | 3 = 15

1
2
3
  1100
| 0011
= 1111

12 & 4 = 4, bo

1
2
3
  1100
&amp; 0100
= 0100

5 ^ 3 = 6, bo

1
2
3
  0101
^ 0011
= 0110

~: negacja bitowa liczby, np. ~12 = -13, bo 12 = ~0000 0000 … 1100 = 1111 1111 … 0011 (zmieniany jest także bit parzystości, liczby w GM mają 8 bajtów, od -9223372036854775808 do +4611686018427387904, dla których oznaczenie INF (nieskończoność) nie pozwala na operacje dodawania / odejmowania)


Funkcje takie jak potęgowanie, pierwiastkowanie, logarytmowanie etc. wykonywane są przez funkcje wbudowane w Game Makera, nie są jednak operatorami, więc do ich poznania polecam lekturę dokumentacji programu.

Tagi: , , , , , , , , , , Brak komentarzy »